home *** CD-ROM | disk | FTP | other *** search
/ Amiga Developer CD 2.1 / Amiga Developer CD v2.1.iso / Reference / DevCon / Atlanta_1990 / Atlanta-Devcon.2 / Libraries / IFFParse / Examples / tree.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-08-26  |  13.4 KB  |  648 lines

  1. /*  :ts=8 bk=0
  2.  *
  3.  * tree.c:    Demonstrater for the hypothetical HTXT form.  A simple
  4.  *        hypertext like structure to demo the more complex 
  5.  *        possibilities for parsing.
  6.  *        Alpha Concept Prototype.
  7.  *
  8.  * Usage: tree -i/o/r <file>
  9.  *
  10.  * Writes and parses HTXT trees between memory and file.  The in-memory
  11.  * structure gets written to the file and the file gets read directly
  12.  * into the same structure using custom handlers.
  13.  *
  14.  *    -i reads the file using custom handlers.
  15.  *    -r reads the file using a recursive-descent parser.
  16.  *    -o writes the demo file.
  17.  *
  18.  * Stuart Ferguson                    8810.18
  19.  * ewhac: adjusted a tiny bit                8811.02
  20.  * shf:   adjusted for Dec 88 revision            8812.18
  21.  * ewhac: Updated to 1.4 Beta                8912.06
  22.  * ewhac: Latticeification                9005.31
  23.  */
  24.  
  25. #include <exec/types.h>
  26. #include <libraries/dos.h>
  27. #include <utility/hooks.h>
  28. #include <libraries/iffparse.h>
  29. #include <clib/exec_protos.h>
  30. #include <clib/dos_protos.h>
  31. #include "iffparse_protos.h"
  32. #include "iffparse.p"
  33.  
  34. #define    ID_HTXT    MAKE_ID('H','T','X','T')
  35. #define    ID_CHRS    MAKE_ID('C','H','R','S')
  36.  
  37. /*
  38.  * Forward function declarations.  (I hate ANSI.)
  39.  */
  40. LONG WriteTree (struct IFFHandle *, struct HNode *);
  41. LONG ReadTree (struct IFFHandle *);
  42. LONG ReadTreeR (struct IFFHandle *);
  43. LONG __saveds __asm TreeHandler (register __a0 struct Hook *, register __a2 struct IFFHandle *, register __a1 LONG *);
  44. LONG __saveds __asm TextHandler (register __a0 struct Hook *, register __a2 struct IFFHandle *, register __a1 LONG *);
  45. LONG __saveds __asm PurgeVHNode (register __a0 struct Hook *, register __a2 struct LocalContextItem *, register __a1 LONG *);
  46. struct HNode *ReadTreeForm (struct IFFHandle *);
  47. char *ReadTextChunk (struct IFFHandle *);
  48. void AddEnd (struct vHNode *, struct HNode *);
  49. void PrintTree (struct HNode *, int);
  50. void FreeTree (struct HNode *);
  51.  
  52.  
  53. /*
  54.  * Tree data structure consists of these types of nodes strung out
  55.  * into trees.  Type is either HN_NODE or HN_LEAF.
  56.  */
  57. struct HNode {
  58.     struct HNode    *next;
  59.     void         *val;
  60.     long        type;
  61. };
  62.  
  63. #define HN_NODE        0
  64. #define HN_LEAF        1
  65.  
  66. /*
  67.  * vHNode's will hold temporary parse states in the local context.
  68.  */
  69. struct vHNode {
  70.     struct HNode        *val;
  71. };
  72. #define LCI_HNODE    MAKE_ID('h','n','o','d')
  73.  
  74. /*
  75.  * Demo text tree structure for output.
  76.  */
  77. struct HNode dtree[] = {
  78.     { NULL, &dtree[1], HN_NODE },
  79.       { &dtree[2], "This is the text body.", HN_LEAF },
  80.       { &dtree[5], &dtree[3], HN_NODE },
  81.         { &dtree[4], "More stuff.", HN_LEAF },
  82.         { NULL, "Even more stuff.", HN_LEAF },
  83.       { NULL, &dtree[6], HN_NODE },
  84.         { NULL, "Nested text ...", HN_LEAF }
  85. };
  86.  
  87.  
  88. /*
  89.  * Buffer for text from IFF file.  Could do this dynamically, but
  90.  * this makes things easier for this simple case.
  91.  */
  92. char    tbuf[500];
  93. int    bufpos = 0;
  94.  
  95. struct Library    *IFFParseBase;
  96.  
  97.  
  98. main (argc, argv)
  99. int    argc;
  100. char    **argv;
  101. {
  102.     struct IFFHandle    *iff = NULL;
  103.     long            error;
  104.     long            filemode;
  105.     int            recur;
  106.  
  107.     if (argc != 3) {
  108.         printf ("usage: %s -i/o/r <file>\n", argv[0]);
  109.         goto die;
  110.     }
  111.  
  112.     if (!(IFFParseBase = OpenLibrary ("iffparse.library", 0L))) {
  113.         puts ("Cannot open library.");
  114.         goto die;
  115.     }
  116.  
  117.     /*
  118.      * Get file i/o direction - 'o' = NEWFILE, 'i/r' = OLDFILE
  119.      */
  120.     filemode = MODE_OLDFILE;
  121.     if (argv[1][1] == 'o')
  122.         filemode = MODE_NEWFILE;
  123.  
  124.     recur = (argv[1][1] == 'r');
  125.  
  126.     /*
  127.      * Standard IFF open sequence:
  128.      *    AllocIFF()
  129.      *    assign stream pointer and setup stream handler vectors
  130.      *    OpenIFF()
  131.      */
  132.     if (!(iff = AllocIFF())) {
  133.         puts ("AllocIFF() failed.");
  134.         goto die;
  135.     }
  136.  
  137.     if (!(iff -> iff_Stream = Open (argv[2], filemode))) {
  138.         puts ("File open failed.");
  139.         goto die;
  140.     }
  141.     InitIFFasDOS (iff);
  142.  
  143.     if (error = OpenIFF
  144.              (iff, filemode==MODE_OLDFILE ? IFFF_READ : IFFF_WRITE))
  145.     {
  146.         puts ("OpenIFF failed.");
  147.         goto die;
  148.     }
  149.  
  150.     if (filemode == MODE_NEWFILE) {
  151.         puts ("writing tree structure...");
  152.         PrintTree (dtree, 1);
  153.         error = WriteTree (iff, dtree);
  154.     } else if (recur)
  155.         error = ReadTreeR (iff);
  156.     else
  157.         error = ReadTree (iff);
  158.  
  159.     if (error)
  160.         printf ("Operation aborted (%ld)\n", error);
  161.  
  162. die:
  163.     /*
  164.      * Standard close sequence (reverse of open):
  165.      *    CloseIFF()
  166.      *    close stream
  167.      *    FreeIFF()
  168.      */
  169.     if (iff) {
  170.         CloseIFF (iff);
  171.         if (iff -> iff_Stream)
  172.             Close (iff -> iff_Stream);
  173.         FreeIFF (iff);
  174.     }
  175.     if (IFFParseBase)    CloseLibrary (IFFParseBase);
  176. }
  177.  
  178.  
  179. /*
  180.  * Write a tree structure to the given IFF stream as a FORM HTXT.
  181.  * Nested trees dealt with recursivly as embedded FORM HTXT's.
  182.  */
  183. LONG
  184. WriteTree (iff, tree)
  185. struct IFFHandle *iff;
  186. struct HNode     *tree;
  187. {
  188.     register struct HNode    *hn;
  189.     register LONG        error, size;
  190.  
  191.     if (!tree)
  192.         return (0);
  193.  
  194.     /*
  195.      * A node structure corresponds to a FORM HTXT chunk with the
  196.      * internal parts of the tree as chunks within this chunk.
  197.      */
  198.     if (tree -> type == HN_NODE) {
  199.         if (error = PushChunk
  200.                  (iff, ID_HTXT, ID_FORM, IFFSIZE_UNKNOWN))
  201.             return (error);
  202.  
  203.         for (hn = tree -> val; hn; hn = hn -> next)
  204.             if (error = WriteTree (iff, hn))
  205.                 return (error);
  206.     /*
  207.      * Leaf nodes correspond to CHRS chunks within their bounding
  208.      * HTXT FORM.
  209.      */
  210.     } else {
  211.         if (error = PushChunk (iff, 0L, ID_CHRS, IFFSIZE_UNKNOWN))
  212.             return (error);
  213.  
  214.         size = strlen (tree -> val);
  215.         if (WriteChunkRecords (iff, tree -> val, 1L, size) != size)
  216.             return (IFFERR_WRITE);
  217.     }
  218.  
  219.     return (PopChunk (iff));
  220. }
  221.  
  222.  
  223. /*
  224.  * Reading uses a custom handler for the HTXT.FORM chunk.  The handler
  225.  * installs a handler for HTXT.CHRS chunks and provides a place for the
  226.  * result of the parse to accumulate.  The end result finishes in the 
  227.  * node at the root level of the structure.
  228.  */
  229. LONG
  230. ReadTree (iff)
  231. struct IFFHandle    *iff;
  232. {
  233.     register struct LocalContextItem *lci;
  234.     register struct HNode         *tree, *hn;
  235.     register struct vHNode         *vhn;
  236.     register struct ContextNode     *top;
  237.     long                 error;
  238.     static struct Hook         treehook = {
  239.         { NULL },
  240.         (ULONG (*)()) TreeHandler,
  241.         NULL,
  242.         NULL
  243.     };
  244.  
  245.     /*
  246.      * Install custom handler for HTXT.FORM chunks and 
  247.      * set up to stop at the end of same.
  248.      */
  249.     if (error = EntryHandler (iff, ID_HTXT, ID_FORM, IFFSLI_ROOT,
  250.                   &treehook, (APTR) iff))
  251.         return (error);
  252.  
  253.     if (error = StopOnExit (iff, ID_HTXT, ID_FORM))
  254.         return (error);
  255.  
  256.     /*
  257.      * Parse that file and let the handlers do their work.
  258.      * Also process end of context conditions for exiting
  259.      * HTXT FORM's.
  260.      */
  261.     while (1) {
  262.         /*
  263.          * SCAN parse will return either EOF at the end of file
  264.          * or EOC for the end of HTXT FORM context or error.
  265.          * Since we'll "break" when exiting the last FORM, even
  266.          * the EOF case can be considered an error.
  267.          */
  268.         error = ParseIFF (iff, IFFPARSE_STEP);
  269.         if (!error) continue;
  270.         if (error != IFFERR_EOC)
  271.             return (error);
  272.  
  273.         top = CurrentChunk (iff);
  274.         if (top -> cn_ID != ID_FORM || top -> cn_Type != ID_HTXT)
  275.             continue;
  276.  
  277.         /*
  278.          * We're about to exit a FORM HTXT, so look for the
  279.          * tree data extracted for this FORM.
  280.          */
  281.         lci = FindLocalItem (iff, 0L, 0L, LCI_HNODE);
  282.  
  283.         if (!lci) {
  284.             puts ("Error looking for result of FORM traversal.");
  285.             tree = NULL;
  286.             break;
  287.         }
  288.  
  289.         /*
  290.          * We're usurping this tree so the purge vector won't
  291.          * try to deallocate it out from under us.
  292.          */
  293.         vhn = (struct vHNode *) LocalItemData (lci);
  294.         tree = vhn -> val;
  295.         vhn -> val = NULL;
  296.  
  297.         /*
  298.          * Here's the kludgy part.
  299.          *
  300.          * We've got the tree for this FORM, so now we need to
  301.          * propogate it backwards in the context stack and 
  302.          * attach it to the tree for the enclosing FORM.
  303.          * So, take the LCI we just found and change the ID
  304.          * field so a subsequent FindLocalItem() will find
  305.          * the enclosing one.  (Need a better way to do this!)
  306.          */
  307.         lci -> lci_ID = 1;
  308.         lci = FindLocalItem (iff, 0L, 0L, LCI_HNODE);
  309.  
  310.         /*
  311.          * If there is no enclosing FORM to be found, we're done.
  312.          */
  313.         if (!lci)
  314.             break;
  315.  
  316.         /*
  317.          * Take the tree found for this current FORM and make
  318.          * make it a sub-tree of the enclosing one.
  319.          */
  320.         if (!(hn = AllocMem ((long) sizeof (*hn), 0L)))
  321.             return (100);
  322.  
  323.         hn -> type = HN_NODE;
  324.         hn -> next = NULL;
  325.         hn -> val = tree;
  326.         AddEnd ((struct vHNode *) LocalItemData (lci), hn);
  327.  
  328.         /*
  329.          * Done processing end of FORM context -- keep parsing.
  330.          */
  331.     }
  332.  
  333.     /*
  334.      * Do something interesting with the result.
  335.      */
  336.     puts ("result of read...");
  337.     PrintTree (tree, 1);
  338.     FreeTree (tree);
  339.  
  340.     return (0);
  341. }
  342.  
  343.  
  344. /*
  345.  * Handler for the HTXT.FORM chunk.  Install a local handler for
  346.  * HTXT.CHRS chunks and provide a place in the current context for
  347.  * result trees to attach themselves.
  348.  */
  349. LONG __saveds __asm
  350. TreeHandler (
  351. register __a0 struct Hook    *hook,
  352. register __a2 struct IFFHandle    *iff,
  353. register __a1 LONG        *cmd
  354. )
  355. {
  356.     register struct LocalContextItem *lci;
  357.     register struct vHNode         *vhn;
  358.     register LONG             error;
  359.     static struct Hook         texthook = {
  360.         { NULL },
  361.         (ULONG (*)()) TextHandler,
  362.         NULL,
  363.         NULL
  364.     };
  365.     static struct Hook         purgehook = {
  366.         { NULL },
  367.         (ULONG (*)()) PurgeVHNode,
  368.         NULL,
  369.         NULL
  370.     };
  371.  
  372.     if (error = EntryHandler (iff, ID_HTXT, ID_CHRS, IFFSLI_TOP,
  373.                   &texthook, (APTR) iff))
  374.         return (error);
  375.  
  376.     if (!(lci = AllocLocalItem (0L, 0L, LCI_HNODE,
  377.                     (long) sizeof (struct vHNode))))
  378.         return (IFFERR_NOMEM);
  379.  
  380.     SetLocalItemPurge (lci, &purgehook);
  381.  
  382.     vhn = (struct vHNode *) LocalItemData (lci);
  383.     vhn -> val = NULL;
  384.  
  385.     if (error = StoreLocalItem (iff, lci, IFFSLI_TOP)) {
  386.         FreeLocalItem (lci);
  387.         return (error);
  388.     }
  389.  
  390.     return (0);
  391. }
  392.  
  393.  
  394. /*
  395.  * Read HTXT.CHRS data into buffer and link into an HNode structure.
  396.  * Attach this HNode to the locally available vHNode in this context.
  397.  */
  398. LONG __saveds __asm
  399. TextHandler (
  400. register __a0 struct Hook    *hook,
  401. register __a2 struct IFFHandle    *iff,
  402. register __a1 LONG        *cmd
  403. )
  404. {
  405.     register struct vHNode    *vhn;
  406.     register struct HNode    *hn;
  407.  
  408.     if (!(hn = AllocMem ((LONG) sizeof (*hn), 0L)))
  409.         return (IFFERR_NOMEM);
  410.  
  411.     hn -> type = HN_LEAF;
  412.     hn -> next = NULL;
  413.     if (!(hn -> val = ReadTextChunk (iff))) {
  414.         FreeTree (hn);
  415.         return (-600);
  416.     }
  417.  
  418.     /*
  419.      * Locate the local vHNode and attach this HNode to it's list.
  420.      */
  421.     if (!(vhn = (struct vHNode *) LocalItemData (
  422.             FindLocalItem (iff, 0L, 0L, LCI_HNODE))))
  423.     {
  424.         FreeTree (hn);
  425.         return (-500);
  426.     }
  427.     AddEnd (vhn, hn);
  428.  
  429.     return (0);
  430. }
  431.  
  432.  
  433. /*
  434.  * Read the contents of a CHRS chunk into a buffer and return pointer.
  435.  */
  436. char *
  437. ReadTextChunk (iff)
  438. struct IFFHandle    *iff;
  439. {
  440.     register LONG    siz;
  441.     register char    *t;
  442.  
  443.     t = &tbuf[bufpos];
  444.     siz = CurrentChunk (iff) -> cn_Size;
  445.     if (ReadChunkBytes (iff, (APTR) t, siz) != siz)
  446.         return (NULL);
  447.  
  448.     bufpos += siz;
  449.     tbuf[bufpos++] = 0;
  450.  
  451.     return (t);
  452. }
  453.  
  454.  
  455. /*
  456.  * Attach HNode to the end of list attached to "vhn".
  457.  * List will be reversed otherwise.
  458.  */
  459. void
  460. AddEnd (vhn, hn)
  461. struct vHNode    *vhn;
  462. struct HNode    *hn;
  463. {
  464.     register struct HNode    *t;
  465.  
  466.     if (!vhn -> val) {
  467.         vhn -> val = hn;
  468.         hn -> next = NULL;
  469.     } else {
  470.         /*
  471.          * Find end of list (next == NULL).
  472.          */
  473.         for (t = vhn -> val; t -> next; t = t -> next)
  474.             ;
  475.         t -> next = hn;
  476.         hn -> next = NULL;
  477.     }
  478. }
  479.  
  480.  
  481. /*
  482.  * If everything goes right, we don't really need to use a special
  483.  * purge vector for vHNodes since the tree will have been removed.
  484.  * If something goes wrong and parsing is inturrupted, however, 
  485.  * CloseIFF() will try to purge all the local context items and
  486.  * this item should be able to clean itself up if it's in an
  487.  * intermediate state.
  488.  */
  489. LONG __saveds __asm
  490. PurgeVHNode (
  491. register __a0 struct Hook        *hook,
  492. register __a2 struct LocalContextItem    *lci,
  493. register __a1 LONG            *cmd
  494. )
  495. {
  496.     register struct vHNode    *vhn;
  497.  
  498.     vhn = (struct vHNode *) LocalItemData (lci);
  499.     if (vhn -> val)
  500.         FreeTree (vhn -> val);
  501.     FreeLocalItem (lci);
  502.  
  503.     return (0);
  504. }
  505.  
  506.  
  507. /*
  508.  * Recursive-descent parser for the HTXT tree structure.
  509.  */
  510. LONG
  511. ReadTreeR (iff)
  512. struct IFFHandle    *iff;
  513. {
  514.     register LONG        error;
  515.     register struct HNode    *tree;
  516.  
  517.     if (error = StopChunk (iff, ID_HTXT, ID_FORM))
  518.         return (error);
  519.  
  520.     if (error = ParseIFF (iff, IFFPARSE_SCAN))
  521.         return (error);
  522.  
  523.     tree = ReadTreeForm (iff);
  524.     if (!tree)
  525.         return (-427);
  526.  
  527.     /*
  528.      * Something interesting ...
  529.      */
  530.     puts ("result of recursive-descent parse ...");
  531.     PrintTree (tree, 1);
  532.     FreeTree (tree);
  533.     return (0);
  534. }
  535.  
  536.  
  537. /*
  538.  * With the iff file positioned just inside a FORM TREE, parse
  539.  * the contents and return as a single HNode.
  540.  */
  541. struct HNode *
  542. ReadTreeForm (iff)
  543. struct IFFHandle    *iff;
  544. {
  545.     register struct HNode        *hn, *sub;
  546.     register struct ContextNode    *top;
  547.     register LONG            error;
  548.  
  549.     if (!(hn = AllocMem ((LONG) sizeof (*hn), 0L)))
  550.         return (NULL);
  551.  
  552.     hn -> type = HN_NODE;
  553.     hn -> next = NULL;
  554.     hn -> val = NULL;
  555.  
  556.     while (1) {
  557.         error = ParseIFF (iff, IFFPARSE_STEP);
  558.         if (error == IFFERR_EOC || error == IFFERR_EOF)
  559.             return (hn);
  560.         if (error)
  561.             goto escape;
  562.  
  563.         top = CurrentChunk (iff);
  564.         if (top->cn_Type != ID_HTXT)
  565.             continue;
  566.  
  567.         switch (top -> cn_ID) {
  568.             case ID_FORM:
  569.             if (!(sub = ReadTreeForm (iff)))
  570.                 goto escape;
  571.             AddEnd ((struct vHNode *) &hn->val, sub);
  572.             break;
  573.  
  574.             case ID_CHRS:
  575.             if (!(sub = AllocMem ((LONG) sizeof (*sub), 0L)))
  576.                 goto escape;
  577.             sub -> type = HN_LEAF;
  578.             sub -> next = NULL;
  579.             if (!(sub -> val = ReadTextChunk (iff))) {
  580.                 FreeTree (sub);
  581.                 goto escape;
  582.             }
  583.             AddEnd ((struct vHNode *) &hn->val, sub);
  584.  
  585.             /*
  586.              * Pop CHRS chunk.
  587.              */
  588.             if (ParseIFF (iff, IFFPARSE_STEP) != IFFERR_EOC)
  589.                 goto escape;
  590.             break;
  591.         }
  592.     }
  593.  
  594. escape:
  595.     FreeTree (hn);
  596.     return (NULL);
  597. }
  598.  
  599.  
  600. void
  601. PrintTree (tree, depth)
  602. struct HNode    *tree;
  603. int        depth;
  604. {
  605.     int i;
  606.  
  607.     if (!tree)
  608.         return;
  609.  
  610.     for (i = 0; i < depth; i++)
  611.         printf (". ");
  612.  
  613.     if (tree -> type == HN_NODE) {
  614.         printf ("node\n");
  615.         PrintTree (tree -> val, depth + 1);
  616.     } else {
  617.         printf ("leaf: %s\n", tree -> val);
  618.     }
  619.     PrintTree (tree -> next, depth);
  620. }
  621.  
  622.  
  623. void
  624. FreeTree (tree)
  625. struct HNode    *tree;
  626. {
  627.     if (!tree)
  628.         return;
  629.  
  630.     if (tree -> type == HN_NODE)
  631.         FreeTree (tree -> val);
  632.     FreeTree (tree -> next);
  633.     FreeMem (tree, (LONG) sizeof (*tree));
  634. }
  635.  
  636. /*
  637.  * Disable Lattice's default ^C trap.
  638.  */
  639. chkabort ()
  640. {
  641.     return (0);
  642. }
  643.  
  644. CXBRK ()
  645. {
  646.     return (0);
  647. }
  648.